//@author A0099223B

import java.util.ArrayList;

// This Parser parses Done Delete View as their formats are similar
public class DDVParser extends Parser {

	private static final boolean BOOLEAN_DONE = true;
	private static final boolean BOOLEAN_NOTDONE = false;
	private static final String MESSAGE_DDV_FAILED = "Delete/Done/View Parsing Failed";
	private static final ArrayList<String> UNUSABLE_TAGS = new ArrayList<String>() {
		{
			add(TAG_START_TIME);
			add(TAG_END_TIME);
			add(TAG_PLACE);
			add(TAG_DESCRIPTION);
			add(TAG_KEYWORD);
			add(TAG_TITLE);
			add(TAG_DONE);
			add(TAG_NOTDONE);
			add(Character.toString(TAG_PROJECT));
		}
	};

	protected static Command parse(String userInput, String commandStart)
			throws InvalidInputException {

		assert ((commandStart.equals(COMMAND_DELETE)
				|| commandStart.equals(COMMAND_DONE)
				|| commandStart.equals(COMMAND_NOTDONE) || commandStart
					.equals(COMMAND_VIEW)) && userInput.toLowerCase()
				.startsWith(commandStart));

		ArrayList<String> unparsedWords = getWordsInCommandDetails(userInput);
		checkForMissingDetails(unparsedWords);

		Command command = new Command();
		String title = attemptToObtainTitle(unparsedWords);

		if (isEmptyString(title)) {
			command = createIdBasedCommand(unparsedWords, commandStart);
		} else {
			command = createTitleBasedCommand(title, unparsedWords,
					commandStart);
		}

		return command;
	}

	// If command uses title to find the task, title should be found right after
	// delete/view/done/not without any tags before it
	private static String attemptToObtainTitle(ArrayList<String> unparsedWords) {
		return extractWordsBeforeNextTag(unparsedWords);
	}

	private static Command createIdBasedCommand(
			ArrayList<String> unparsedWords, String commandStart)
			throws InvalidInputException {

		checkTags(unparsedWords, commandStart);
		int id = obtainId(unparsedWords);
		return createGivenTypeOfCommand(commandStart, id);
	}

	private static void checkTags(ArrayList<String> unparsedWords,
			String commandStart) throws InvalidInputException {

		checkForUnusableStringTags(UNUSABLE_TAGS, unparsedWords, commandStart);
		checkForRepeatingTags(unparsedWords);
	}

	private static int obtainId(ArrayList<String> unparsedWords)
			throws InvalidInputException {
		String idString = extractTaggedClause(TAG_ID, unparsedWords);
		ifNullNoTaskReferenced(idString);

		return parseId(idString);
	}

	private static Command createGivenTypeOfCommand(String commandStart, int id) {
		assert (commandStart.equals(COMMAND_DELETE)
				|| commandStart.equals(COMMAND_DONE)
				|| commandStart.equals(COMMAND_NOTDONE) || commandStart
					.equals(COMMAND_VIEW));

		switch (commandStart) {
		case COMMAND_DELETE:
			return createDeleteCommand(id);
		case COMMAND_DONE:
			return createDoneCommand(id, BOOLEAN_DONE);
		case COMMAND_NOTDONE:
			return createDoneCommand(id, BOOLEAN_NOTDONE);
		case COMMAND_VIEW:
			return createViewCommand(id);
		}

		// Shouldn't execute
		return null;

	}

	private static Command createTitleBasedCommand(String taskTitle,
			ArrayList<String> unparsedWords, String commandStart)
			throws InvalidInputException {
		assert (commandStart.equals(COMMAND_DELETE)
				|| commandStart.equals(COMMAND_DONE)
				|| commandStart.equals(COMMAND_NOTDONE) || commandStart
					.equals(COMMAND_VIEW));

		ensureNoIdReference(unparsedWords);
		checkForUnusableStringTags(UNUSABLE_TAGS, unparsedWords, commandStart);

		return createGivenTypeOfCommand(commandStart, taskTitle);
		
	}

	private static Command createGivenTypeOfCommand(String commandStart,
			String taskTitle) {
		assert (commandStart.equals(COMMAND_DELETE)
				|| commandStart.equals(COMMAND_DONE)
				|| commandStart.equals(COMMAND_NOTDONE) || commandStart
					.equals(COMMAND_VIEW));

		switch (commandStart) {
		case COMMAND_DELETE:
			return createDeleteCommand(taskTitle);
		case COMMAND_DONE:
			return createDoneCommand(taskTitle, BOOLEAN_DONE);
		case COMMAND_NOTDONE:
			return createDoneCommand(taskTitle, BOOLEAN_NOTDONE);
		case COMMAND_VIEW:
			return createViewCommand(taskTitle);
		}
		// Shouldn't execute
		return null;
	}

	private static Command createDeleteCommand(int taskId) {
		DeleteCommand deleteCommand = new DeleteCommand();
		deleteCommand.taskId = taskId;
		return deleteCommand;
	}

	private static Command createDeleteCommand(String taskTitle) {
		DeleteCommand deleteCommand = new DeleteCommand();
		deleteCommand.taskTitle = taskTitle;
		return deleteCommand;
	}

	private static Command createDoneCommand(int taskId, boolean isDone) {
		DoneCommand doneCommand = new DoneCommand();
		doneCommand.taskId = taskId;
		doneCommand.isDone = isDone;

		return doneCommand;
	}

	private static Command createDoneCommand(String taskTitle, boolean isDone) {
		DoneCommand doneCommand = new DoneCommand();
		doneCommand.taskTitle = taskTitle;
		doneCommand.isDone = isDone;

		return doneCommand;
	}

	private static Command createViewCommand(int taskId) {
		ViewCommand viewCommand = new ViewCommand();
		viewCommand.taskId = taskId;
		return viewCommand;
	}

	private static Command createViewCommand(String taskTitle) {
		ViewCommand viewCommand = new ViewCommand();
		viewCommand.taskTitle = taskTitle;
		return viewCommand;
	}

}
